﻿using System;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using YArchitech.Revit;

namespace YJKRevitAxisModule
{
	public class GridsMerge
	{
		public GridsMerge(ExternalCommandData cmdData)
		{
			this.m_cmdData = cmdData;
		}

		public Result Run(ref string message)
		{
			Result result;
			try
			{
                if (Autodesk.Revit.UI.Result.Failed == this.SelectGrid())
				{
					throw new System.ArgumentNullException();
				}
                if (Autodesk.Revit.UI.Result.Failed == this.Merge())
				{
					throw new Exception("轴线合并失败！");
				}
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception ex)
			{
				message = ex.Message;
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private Result SelectGrid()
		{
			Selection selection = this.m_cmdData.Application.ActiveUIDocument.Selection;
			RevitVersionFuncs.ClearSelection(selection);
			Result result;
			try
			{
				AxisFilter axisFilter = new AxisFilter();
				Reference reference = selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, axisFilter, "选择轴线");
				this.m_elePrimary = this.m_cmdData.Application.ActiveUIDocument.Document.GetElement(reference);
				this.m_xyzPri = reference.GlobalPoint;
				reference = selection.PickObject((Autodesk.Revit.UI.Selection.ObjectType)1, axisFilter, "选择另一根轴线");
				this.m_eleSecondary = this.m_cmdData.Application.ActiveUIDocument.Document.GetElement(reference);
				this.m_xyzSec = reference.GlobalPoint;
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private Result Merge()
		{
			if (this.MergeGridWithSameTrack())
			{
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			if (this.MergeGridWithIntersection())
			{
				return Autodesk.Revit.UI.Result.Succeeded;
			}
			return Autodesk.Revit.UI.Result.Failed;
		}

		private bool MergeGridWithSameTrack()
		{
			Grid grid = this.m_elePrimary as Grid;
			Grid grid2 = this.m_eleSecondary as Grid;
			if (grid != null && grid2 != null)
			{
				Line line = grid.Curve as Line;
				Line line2 = grid2.Curve as Line;
				if (null != line && null != line2 && new YJKLine(line2).IsLineOnLine(line))
				{
					XYZ hyendPoint = line.GetEndPoint(0);
					XYZ hyendPoint2 = line.GetEndPoint(1);
					XYZ hyendPoint3 = line2.GetEndPoint(0);
					XYZ hyendPoint4 = line2.GetEndPoint(1);
					XYZ xyz = XYZ.Zero;
					XYZ xyz2 = XYZ.Zero;
					double num = line.Distance(hyendPoint3);
					double num2 = line.Distance(hyendPoint4);
					if (num > num2)
					{
						xyz = hyendPoint3;
					}
					else
					{
						xyz = hyendPoint4;
					}
					double num3 = xyz.DistanceTo(hyendPoint);
					num2 = xyz.DistanceTo(hyendPoint2);
					if (num3 > num2)
					{
						xyz2 = hyendPoint;
					}
					else
					{
						xyz2 = hyendPoint2;
					}
					XYZ vector = LineAssistFunc.GetVector(line);
					XYZ secondVec = xyz2 - xyz;
					try
					{
						Line line3;
						if (GeoUtil.IsSameDirection(vector, secondVec))
						{
							line3 = this.m_cmdData.Application.Application.CreatYJKLine(xyz, xyz2, true);
						}
						else
						{
							line3 = this.m_cmdData.Application.Application.CreatYJKLine(xyz2, xyz, true);
						}
						Grid grid3 = this.m_cmdData.Application.ActiveUIDocument.Document.YjkNewGrid(line3);
						string name = grid.Name;
						grid3.ChangeTypeId(grid.GetGridType().Id);
						this.m_cmdData.Application.ActiveUIDocument.Document.Delete(this.m_elePrimary.Id);
						this.m_cmdData.Application.ActiveUIDocument.Document.Delete(this.m_eleSecondary.Id);
						grid3.Name = name;
					}
					catch
					{
						return false;
					}
					return true;
				}
			}
			return false;
		}

		private bool MergeGridWithIntersection()
		{
			try
			{
				List<Curve> list = this.TransformCurvesByGrid(this.m_elePrimary);
				List<Curve> list2 = this.TransformCurvesByGrid(this.m_eleSecondary);
				XYZ intersectPoint = this.GetIntersectPoint(list, list2);
				if (intersectPoint == null)
				{
					YJKMessageBox.Show("两根轴线不相交。");
					return true;
				}
				List<Curve> ar = new List<Curve>();
				List<Curve> ar2 = new List<Curve>();
				List<Curve> ar3 = new List<Curve>();
				List<Curve> ar4 = new List<Curve>();
				this.SplitListByPoint(list, intersectPoint, ref ar, ref ar2);
				this.SplitListByPoint(list2, intersectPoint, ref ar3, ref ar4);
				list = this.GetCurveListByPoint(ar, ar2, this.m_xyzPri);
				list2 = this.GetCurveListByPoint(ar3, ar4, this.m_xyzSec);
				List<Curve> arCurves = new List<Curve>();
				arCurves = this.MergeCurveListByOrder(list, list2, intersectPoint);
				Document document = this.m_cmdData.Application.ActiveUIDocument.Document;
				CurveLoop conCurvesLoop = AxisAssistFunc.GetConCurvesLoop(this.m_cmdData.Application, arCurves);
				ElementId typeId = this.m_elePrimary.GetTypeId();
				Plane plane = RevitVersionFuncs.CreatePlanByNormalAndOrigin(XYZ.BasisZ, intersectPoint);
				ElementId id = SketchPlane.Create(this.m_cmdData.Application.ActiveUIDocument.Document, plane).Id;
				ElementId elementId = RevitDocumentExtension.CreateMultiSegmentGrid(document, typeId, conCurvesLoop, id);
				document.GetElement(elementId).Name = this.m_elePrimary.Name;
				this.m_cmdData.Application.ActiveUIDocument.Document.Delete(this.m_elePrimary.Id);
				this.m_cmdData.Application.ActiveUIDocument.Document.Delete(this.m_eleSecondary.Id);
			}
			catch (Exception ex)
			{
				string message = ex.Message;
				return false;
			}
			return true;
		}

		private List<Curve> TransformCurvesByGrid(Element ele)
		{
			List<Curve> list = new List<Curve>();
			if (ele.GetType() == typeof(MultiSegmentGrid))
			{
				MultiSegmentGrid grid = ele as MultiSegmentGrid;
				list = AxisAssistFunc.GetLocationCurves(this.m_cmdData.Application, this.m_cmdData.Application.ActiveUIDocument.Document, grid);
			}
			else if (ele.GetType() == typeof(Grid))
			{
				Grid grid2 = ele as Grid;
				list.Add(grid2.Curve);
			}
			return list;
		}

		private XYZ GetIntersectPoint(List<Curve> arCurvesPri, List<Curve> arCurvesSec)
		{
			XYZ xyz = null;
			IntersectionResultArray intersectionResultArray = new IntersectionResultArray();
			foreach (Curve curve in arCurvesPri)
			{
				foreach (Curve curve2 in arCurvesSec)
				{
					SetComparisonResult setComparisonResult = curve.Intersect(curve2, out intersectionResultArray);
					if (4 != (int)setComparisonResult && intersectionResultArray != null && !intersectionResultArray.IsEmpty)
					{
						xyz = intersectionResultArray.get_Item(0).XYZPoint;
						if (xyz != null)
						{
							return xyz;
						}
					}
				}
			}
			return xyz;
		}

		private Result SplitListByPoint(List<Curve> arCurves, XYZ point, ref List<Curve> ar1, ref List<Curve> ar2)
		{
			int num = 0;
			IntersectionResult intersectionResult = new IntersectionResult();
			foreach (Curve curve in arCurves)
			{
				intersectionResult = curve.Project(point);
				if (intersectionResult != null && intersectionResult.XYZPoint != null && point.IsAlmostEqualTo(intersectionResult.XYZPoint))
				{
					XYZ endPoint = curve.GetEndPoint(0);
					XYZ endPoint2 = curve.GetEndPoint(1);
					if (curve.GetType() == typeof(Line))
					{
						if (!point.IsAlmostEqualTo(endPoint))
						{
							ar1.Add(Line.CreateBound(endPoint, point));
						}
						if (!point.IsAlmostEqualTo(endPoint2))
						{
							ar2.Add(Line.CreateBound(point, endPoint2));
						}
					}
					else if (curve.GetType() == typeof(Arc))
					{
						Arc arc = curve as Arc;
						XYZ center = arc.Center;
						XYZ normal = arc.Normal;
						XYZ xyz = AxisAssistFunc.CalculatMidPoint(endPoint, point, center, normal);
						XYZ xyz2 = AxisAssistFunc.CalculatMidPoint(point, endPoint2, center, normal);
						if (!endPoint.IsAlmostEqualTo(point))
						{
							Arc item = Arc.Create(endPoint, point, xyz);
							ar1.Add(item);
						}
						if (!endPoint2.IsAlmostEqualTo(point))
						{
							Arc item2 = Arc.Create(point, endPoint2, xyz2);
							ar2.Add(item2);
						}
					}
					num++;
				}
				else if (num == 0)
				{
					ar1.Add(curve);
				}
				else
				{
					ar2.Add(curve);
				}
			}
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private List<Curve> GetCurveListByPoint(List<Curve> ar1, List<Curve> ar2, XYZ point)
		{
			if (ar1.Count == 0)
			{
				return ar2;
			}
			if (ar2.Count == 0)
			{
				return ar1;
			}
			XYZ xyz = new XYZ(point.X, point.Y, 0.0);
			new IntersectionResult();
			double num = ar1[0].Distance(xyz);
			double num2 = ar2[0].Distance(xyz);
			foreach (Curve curve in ar1)
			{
				double num3 = curve.Distance(xyz);
				if (num3 < num)
				{
					num = num3;
				}
			}
			foreach (Curve curve2 in ar2)
			{
				double num4 = curve2.Distance(xyz);
				if (num4 < num2)
				{
					num2 = num4;
				}
			}
			if (num < num2)
			{
				return ar1;
			}
			return ar2;
		}

		private List<Curve> MergeCurveListByOrder(List<Curve> ar1, List<Curve> ar2, XYZ point)
		{
			List<Curve> list = new List<Curve>();
			List<Curve> list2 = new List<Curve>();
			if (GeoUtil.IsPointEqual(ar1[0].GetEndPoint(0), point))
			{
				ar1.Reverse();
				using (List<Curve>.Enumerator enumerator = ar1.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						Curve curve = enumerator.Current;
						Curve item = AxisAssistFunc.CalculateReverseCurve(this.m_cmdData.Application, curve);
						list.Add(item);
					}
					goto IL_6E;
				}
			}
			list = ar1;
			IL_6E:
			if (!GeoUtil.IsPointEqual(ar2[0].GetEndPoint(0), point))
			{
				ar2.Reverse();
				using (List<Curve>.Enumerator enumerator = ar2.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						Curve curve2 = enumerator.Current;
						Curve item2 = AxisAssistFunc.CalculateReverseCurve(this.m_cmdData.Application, curve2);
						list2.Add(item2);
					}
					goto IL_D2;
				}
			}
			list2 = ar2;
			IL_D2:
			foreach (Curve item3 in list2)
			{
				list.Add(item3);
			}
			return list;
		}

		protected ExternalCommandData m_cmdData;

		private Element m_elePrimary;

		private Element m_eleSecondary;

		private XYZ m_xyzPri;

		private XYZ m_xyzSec;
	}
}
